package sf.common.log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sf.database.OrmConfig;
import sf.database.template.sql.SqlHelp;
import sf.tools.ArrayUtils;
import sf.tools.StringUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

public class OrmLog {
    private static Logger log = LoggerFactory.getLogger(OrmLog.class);

    public static int LENGTH = 50;

    public static String lineSeparator = System.getProperty("line.separator", "\n");

    public static void commonListLog(String sql, List<Object> paras) {
        commonListLog(sql, true, paras);
    }

    public static void commonListLog(String sql, boolean format, List<Object> paras) {
        if (sql == null) {
            return;
        }
        //是否开启日志打印
        if (OrmConfig.getInstance().isShowSql()) {
            StringBuilder sb = new StringBuilder();

            sb.append(lineSeparator);
            if (format && (sql.contains("\r") || sql.contains("\n") || sql.contains("\t"))) {
                sql = SqlHelp.replaceLineSql(sql);
            }
            sb.append("SQL: ").append(sql);
            if (paras != null) {
                for (Object p : paras) {
                    String value = String.valueOf(p);
                    if (value.length() >= LENGTH) {
                        value = value.substring(0, LENGTH) + "...(" + value.length() + ")";
                    }
                    sb.append(lineSeparator).append("Param ====>>> ").append(value);
                }
            }
            println(sb);
        }
    }

    public static void commonArrayLog(String sql, Object... paras) {
        commonArrayLog(sql, true, paras);
    }

    public static void commonArrayLog(String sql, boolean format, Object... paras) {
        if (sql == null) {
            return;
        }
        //是否开启日志打印
        if (OrmConfig.getInstance().isShowSql()) {
            StringBuilder sb = new StringBuilder();
            sb.append(lineSeparator);
            if (format && (sql.contains("\r") || sql.contains("\n") || sql.contains("\t"))) {
                sql = SqlHelp.replaceLineSql(sql);
            }
            sb.append("SQL: ").append(sql);
            if (paras != null) {
                for (Object p : paras) {
                    String value = String.valueOf(p);
                    if (value.length() >= LENGTH) {
                        value = value.substring(0, LENGTH) + "...(" + value.length() + ")";
                    }
                    sb.append(lineSeparator).append("Param ====>>> ").append(value);
                }
            }
            println(sb);
        }
    }

    public static void batchCommonLog(String sql, int all, int current, Object... paras) {
        batchCommonLog(sql, true, all, current, paras);
    }

    public static void batchCommonLog(String sql, boolean format, int all, int current, Object... paras) {
        if (sql == null) {
            return;
        }
        if (OrmConfig.getInstance().isShowSql()) {
            StringBuilder sb = new StringBuilder();
            if (format && (sql.contains("\r") || sql.contains("\n") || sql.contains("\t"))) {
                sql = SqlHelp.replaceLineSql(sql);
            }
            sb.append("Batch:").append(current).append("/").append(all).append(" ").append(sql);
            if (paras != null) {
                for (Object p : paras) {
                    String value = String.valueOf(p);
                    if (value.length() >= LENGTH) {
                        value = value.substring(0, LENGTH) + "...(" + value.length() + ")";
                    }
                    sb.append(lineSeparator).append("Param ====>>> ").append(value);
                }
            }
            println(sb);
        }
    }

    public static void resultLog(long start) {
        resultLog(start, null, null);
    }

    public static void resultLog(long start, Object result, Connection conn) {
        if (OrmConfig.getInstance().isShowSql()) {
            StringBuilder sb = new StringBuilder();
            sb.append("Time cost: ").append((System.currentTimeMillis() - start)).append("ms");
            if (OrmConfig.getInstance().isUseSystemPrint()) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                sb.append(" ").append("Execute time: ").append(sdf.format(new Date()));
            }
            Boolean autoCommit = null;
            if (conn != null) {
                try {
                    autoCommit = conn.getAutoCommit();
                } catch (SQLException e) {

                }
            }
            if (autoCommit != null) {
                sb.append(", ").append("AutoCommit: ").append(autoCommit);
            }
            if (result != null) {
                if (result instanceof Collection) {
                    sb.append(lineSeparator).append("Result:  [").append(((Collection<?>) result).size()).append("]");
                } else if (result.getClass().isArray()) {
                    String r = StringUtils.join(ArrayUtils.objectToArray(result), ",");
                    sb.append(lineSeparator).append("Result:  [").append(r).append("]");
                } else {
                    sb.append(lineSeparator).append("Result:  [").append(result).append("]");
                }
            }

            //是否需要打印方法调用链
            if (OrmConfig.getInstance().isShowCallChain()) {
                RuntimeException ex = new RuntimeException();
                StackTraceElement[] traces = ex.getStackTrace();
                List<StackTraceElement> list = lookBusinessCodeInTrace(traces);
                sb.append(lineSeparator).append("CallChain: ");
                sb.append(list.toString());
            }
            sb.append(lineSeparator);
            println(sb);
        }
    }

    protected static void println(StringBuilder sb) {
        //是否使用系统打印日志
        if (OrmConfig.getInstance().isUseSystemPrint()) {
            System.out.println(sb);
        } else {
            String str = sb.toString();
            if (!str.startsWith(lineSeparator)) {
                str = lineSeparator + str;
            }
            if (log.isInfoEnabled()) {
                log.info(str);
            }
        }
    }

    protected static List<StackTraceElement> lookBusinessCodeInTrace(StackTraceElement[] traces) {
        List<StackTraceElement> list = new ArrayList<>();
        for (int i = 1; i < traces.length - 1; i++) {
            String name = traces[i].getClassName();
            list.add(traces[i]);
            if (!name.startsWith("sf") && !name.contains("$")) {
                break;
            }
        }
        return list;
    }
}
